昨天學會了如何利用粒子系統做爆炸特效,今天我們要來將特效套用至專案中,來實作苦力怕自爆的效果,並且利用更多層的爆炸、由黑到白不同的顏色,來模擬得更真實一些。
Photo by Cristian Escobar on Unsplash
這是本系列第 18 篇,如果還沒看過第 17 篇可以點以下連結前往:
用 Three.js 來當個創世神 (17):粒子系統 - 爆炸
在實作之前,最重要的是先觀察預期的爆炸效果是怎麼樣的,這邊找到另一個有慢動作的苦力怕爆炸影片。從慢動作可以觀察到,苦力怕的爆炸有以下幾個重點:
瞭解了狀況之後以下就開始來實作了!
請參考完整原始碼及成果展示,使用 explosionTrigger
來觸發苦力怕爆炸、 resetCreeper
來重置苦力怕。
不知道是不是筆者每天被鐵人賽 deadline 追趕壓力大,實際上操作起來好像也蠻像舒壓小遊戲的。
這邊我們拿第 11 篇的模板來做,在那篇文章中,已經準備好了苦力怕爆炸的前置膨脹動作,而剩下的就是要將爆炸特效套上去並模擬得更像一些,就可以完成了。
首先先將上一篇中的 Explosion
物件加進去:
// points
const pointCount = 1000
const movementSpeed = 10
let explosion = [] // 爆炸物件陣列
let size = 10
const smokeTexture = textureLoader.load('./smoke.png')
class Explosion {
constructor(x, y, z, color) {
...
this.material = new THREE.PointsMaterial({
size: size,
color: color,
map: smokeTexture,
blending: THREE.CustomBlending,
depthWrite: false,
transparent: true,
opacity: 0.7
})
...
}
...
}
主要是做一些參數的調整來讓爆炸效果更像,除了比較基本的粒子數、爆炸速度、粒子尺寸外,這裡讓新增爆炸物件時還能定義粒子顏色,而這邊各層爆炸的顏色下面會指定由黑到白共五種顏色,但遇到一個問題是不管怎麼改都是白色,後來在各種 try & error 後也將各種融合模式試了一輪:
THREE.NoBlending
THREE.NormalBlending
THREE.AdditiveBlending
THREE.SubtractiveBlending
THREE.MultiplyBlending
THREE.CustomBlending
後來改為 THREE.CustomBlending
時就成功了,看文件這種融合模式還可以設定幾種不同的算法,不過文件也沒提到這幾種融合模式差在哪,稍微 google 一下後意外地找到這篇文章中有個 depthWrite: false
覺得很眼熟,設定這個屬性後爆炸粒子就可以正確穿透地板,也一起去把前面第 15 篇中關於 depthTest
的問題修正了。
詳細的原因應可參考這篇,大概瀏覽的意思應是
depthTest
會關掉比較多遮蔽的效果,而其他圖學的內容之後有空再來深入研究。
this.explosionTrigger = function() {
for (let i = 0; i < scene.children.length; i++) {
const object = scene.children[i]
// 場景內有苦力怕才爆炸
if (object.name === 'creeper') {
// 清除之前爆炸粒子
if (explosion) {
const len = explosion.length
if (len > 0) {
for (let i = 0; i < len; i++) {
explosion[i].destroy()
}
}
explosion.length = 0
}
// 移除苦力怕
scene.remove(creeperObj.creeper)
// 產生爆炸
explosion[0] = new Explosion(0, 0, 0, 0x000000)
explosion[1] = new Explosion(5, 5, 5, 0x333333)
explosion[2] = new Explosion(-5, 5, 10, 0x666666)
explosion[3] = new Explosion(-5, 5, 5, 0x999999)
explosion[4] = new Explosion(5, 5, -5, 0xcccccc)
}
}
}
這邊利用 dat.GUI 做一個觸發爆炸的開關,首先簡單做了一下防呆,就是當場景中沒有苦力怕物件時就不做爆炸效果,若有的話則先清掉之前的爆炸粒子殘骸,然後在爆炸前先把苦力怕從場景中移除。
而這裡新的 explosion
改為陣列,總共觸發五個爆炸,分別給予不同的爆炸中心與由黑到白的顏色,讓爆炸的煙霧更逼真一些。
this.resetCreeper = function() {
scene.add(creeperObj.creeper)
}
重置則非常單純,只是將苦力怕加回場景。
function render() {
if (explosion) {
const len = explosion.length
if (len > 0) {
for (let i = 0; i < len; i++) {
explosion[i].update()
}
}
}
...
requestAnimationFrame(render)
renderer.render(scene, camera)
}
爆炸動畫的設定也很單純,只做了每個爆炸的 update()
,原本有考慮加上爆炸時間差的效果,但暫時還沒做出來,就只先將爆炸速度調快達到比較像的爆炸效果。
// 相機設定
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
20,
1000
)
camera.position.set(50, 50, 50)
camera.lookAt(scene.position)
前面提到關於相機近平面距離這裡設 20
。
還可以補上每一層爆炸間的時間差,效果會更逼真。
在粒子材質中,關於融合模式與 dapthTest、depthWrite 不算完全理解他們的作用,可以再深入研究。
今天完成了苦力怕的自爆動畫,也替粒子系統與專案中苦力怕相關的部分做個收尾,明天開始會進入第二部分來研究物理引擎,之後會開始實做遊戲中的射擊效果,我們明天見!